Стоимость
сложения двух чисел равна их сумме. То есть, чтобы прибавить 10 к 1, следует
заплатить 11. В задаче требуется сложить все заданные числа так, чтобы потратить наименьшую
сумму денег.
Например,
складывать числа 1, 2 и 3 можно одним из трех способов:
· 1 + 2 = 3 (стоимость
= 3), 3 + 3 = 6 (стоимость = 6). Всего
= 9
· 1 + 3 = 4 (стоимость
= 4), 2 + 4 = 6 (стоимость = 6). Всего
= 10
· 2 + 3 = 5 (стоимость
= 5), 1 + 5 = 6 (стоимость = 6). Всего
= 11
Первый способ
сложения является
самым дешевым.
Вход. Первая строка содержит натуральное число n (2 ≤ n ≤ 105). Вторая строка содержит n
целых неотрицательных чисел, каждое из которых не превышает 105.
Выход. Выведите
наименьшую стоимость сложения всех чисел.
Пример
входа |
Пример
выхода |
4 1 2 3 4 |
19 |
жадность
Анализ алгоритма
Пример
Для минимизации
стоимости сложения будем складывать числа в следующем порядке:
1. Складываем 1 и
2, получим 3. Стоимость сложения 3.
2. Складываем 3 и
3, получим 6. Стоимость сложения 6.
3. Складываем 4 и
6, получим 10. Стоимость сложения 10.
Общая стоимость
сложения равна 3 + 6 + 10 = 19.
Реализация алгоритма
Входные числа
храним в мультимножестве s (числа
могут повторяться). Два наименьших числа всегда располагаются в начале мультимножества.
multiset<long
long> s;
Читаем
количество чисел n.
scanf("%lld",&n);
Читаем
последовательность слагаемых и добавляем их в мультимножество s.
for (i = 0; i <
n; i++)
{
scanf("%lld",&x);
s.insert(x);
}
В переменной res вычисляем стоимость сложений всех
чисел.
res = 0;
Пока в мультимножестве s
больше одного числа, извлекаем и складываем два его наименьших элемента и добавляем их
сумму обратно в s. Стоимость сложения чисел a и b равна a + b, и она прибавляется к res.
while (s.size() >
1)
{
a = *s.begin(); s.erase(s.begin());
b = *s.begin(); s.erase(s.begin());
s.insert(a + b);
res += a + b;
}
Когда в
мультимножестве остаётся только одно число, выводим ответ – значение переменной res.
printf("%lld\n",res);
Реализация при
помощи очереди с приоритетами
Объявим очередь с приоритетами pq, в начале которой всегда находится наименьший элемент.
priority_queue<long long, vector<long long>,
greater<long long>
> pq;
Читаем
количество чисел n.
scanf("%lld",&n);
Читаем
последовательность слагаемых и добавляем их в очередь с приоритетами pq.
scanf("%lld",&n);
for (i = 0; i <
n; i++)
{
scanf("%lld",&x);
pq.push(x);
}
В переменной res вычисляем стоимость сложений всех
чисел.
res = 0;
Пока в очереди pq больше одного числа, извлекаем и складываем два его наименьших элемента и добавляем их
сумму обратно в pq. Стоимость
сложения чисел a и b равна a + b, и она прибавляется к res.
while (pq.size() >
1)
{
a = pq.top(); pq.pop();
b = pq.top(); pq.pop();
pq.push(a + b);
res += a + b;
}
Когда в очереди остаётся только одно число,
выводим ответ – значение переменной res.
printf("%lld\n",res);
Java реализация
import java.util.*;
public class Main
{
public static void main(String[] args)
{
Scanner con = new Scanner(System.in);
int n = con.nextInt();
PriorityQueue<Long> pq = new PriorityQueue<Long>();
for(int i = 0; i < n; i++)
{
long val = con.nextLong();
pq.add(new Long(val));
}
long Result = 0;
while(pq.size() > 1)
{
long a = pq.poll();
long b = pq.poll();
pq.add(a + b);
Result += a + b;
}
System.out.println(Result);
}
}
Python реализация
Объявим очередь с приоритетами q, в начале которой всегда находится наименьший элемент.
from
queue import
PriorityQueue
q = PriorityQueue()
Читаем входные
данные.
n = int(input())
lst = map(int,input().split())
Добавим слагаемые
в очередь q.
for
x in
lst:
q.put(x)
В переменной res вычисляем стоимость сложений всех
чисел.
res = 0
Пока в очереди q больше одного числа, извлекаем и складываем два его наименьших элемента и добавляем их
сумму обратно в q. Стоимость сложения
чисел a и b равна a + b, и она прибавляется к res.
while
q.qsize() > 1:
a = q.get()
b = q.get()
q.put(a + b)
res += a + b
Когда в очереди остаётся только одно число,
выводим ответ – значение переменной res.
print(res)